package org.jmh.auth.service.impl;

import org.jmh.auth.domain.Permission;
import org.jmh.auth.service.IPermissionService;
import org.jmh.auth.service.IpermissionScanService;
import org.jmh.base.annotation.JmhPermission;
import org.jmh.base.enums.RequestTypeEnum;
import org.jmh.base.util.ClassUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

@Service
public class PermissionScanServiceImpl implements IpermissionScanService {
    @Autowired
    private IPermissionService service;

    @Value("${package-scan.url}")
    private String url;


    @Override
    @Transactional
    public void scan() throws ClassNotFoundException {
        service.deleteAll();
//        获取所有的Controller字节码对象
//        拿到项目的位置
        List<Class> list = ClassUtils.getAllClassName(url);
//        list.forEach(System.out::println);
//        循环字节码对象
        for (Class clazz : list){
            JmhPermission annotation = (JmhPermission)clazz.getAnnotation(JmhPermission.class);
            if(annotation !=null){
                //当annotation不为空，说明类上有权限注解
                Permission parent = new Permission();
                parent.setName(annotation.name());
                parent.setDescs(annotation.desc());
//                  sn=类名+方法名
                parent.setSn(clazz.getSimpleName());
//                  url=资源路径=Controller的requestMapping+xxxMapping
                RequestMapping annotation2 = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
//                  类上的url
                String clazzUrl = annotation2.value()[0];
//                  方法上的url
                parent.setUrl(clazzUrl);
                parent.setParent(null);
//                父类对象先入库
                service.insert(parent);
//                获取方法
                Method[] methods = clazz.getMethods();
//                拼接数据
                for(Method method:methods){
                    JmhPermission annotation1 = method.getAnnotation(JmhPermission.class);
                    if(annotation1!=null){
                        Permission permission = new Permission();
                        permission.setName(annotation1.name());
                        permission.setDescs(annotation1.desc());
//                  sn=类名+方法名
                        permission.setSn(clazz.getSimpleName() + ":" + method.getName());
//                  方法上的url
                        String methodUrl = getMethodUrl(method);
                        permission.setUrl(clazzUrl+methodUrl);
                        permission.setParent(parent);
//                  入库
                        service.insert(permission);
                    }
                }
            }
        }
    }


    public String getMethodUrl(Method method){
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if(Objects.isNull(annotation)){
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Class<? extends Annotation> aClass = annotation.annotationType();
                // aClass 是 对应的 请求类型的  字节码对象
                Method annotationMethod = aClass.getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                // 反射执行 方法 方法名.invoke(对象)

                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if(value != null && value.length > 0){
                    methodUrl = value[0];
                    break;
                }
            }catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;

    }
}
